﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;
using System.IO;

namespace Xceed.Silverlight.ListBox
{
  // This is a hack to keep the same API
  // as ItemsControl, ItemsPresenter, and ItemsPanelTemplate,
  // but the types are not of the same base class.
  // This class is intended to be used only in the ListBox
  // ControlTemplate as the ItemsPanel placeholder.
  public sealed class ItemsPresenter : ContentControl, IScrollInfo
  {
    #region Contructors

    public ItemsPresenter()
    {
      // The ItemsPresenter itself must not be IsTabStop.
      // The control itself behaves differently than the
      // MS ListBox because we only try to have the same 
      // API. This is also the reason why we set TabNavigation
      // to Once to avoid local navigation on each Children
      // of the PanelBase that will contain every containers
      // of the ListBox.
      this.IsTabStop = false;
#if SILVERLIGHT
      this.TabNavigation = KeyboardNavigationMode.Once;
#else
      this.SetValue( KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Once );
#endif
    }

    #endregion

    #region Static Fields

    private static string DefaultItemsPanelTemplateString =
      @"<sllb:ItemsPanelTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" "
      + @"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" "
      + @"xmlns:sllb=""clr-namespace:Xceed.Silverlight.ListBox;assembly=Xceed.Silverlight.ListBox.v2.0"">"
      + @"<sllb:StackPanel Orientation=""Vertical""/>"
      + @"</sllb:ItemsPanelTemplate>";

    #endregion

    #region Internal Methods

    internal void InitializeAndLoadItemsPanelTemplate()
    {
      // Get the top most Parent, meaning the root element
      // of the ControlTemplate's scrope
      FrameworkElement parent = this.Parent as FrameworkElement;

      while( parent != null )
      {
        parent = parent.Parent as FrameworkElement;

        if( parent.Parent == null )
          break;
      }

      if( parent == null )
        throw new ListBoxInternalException( "The ItemsPresenter has no parent." );

      // Use VisualTreeHelper to get the "Logical Parent" of the root element
      // which is the TemplatedParent, not directly available in Silverlight
      ListBox listBox = VisualTreeHelper.GetParent( parent ) as ListBox;

      ItemsPanelTemplate itemsPanelTemplate = null;

      if( listBox != null )
        itemsPanelTemplate = listBox.ItemsPanel;

      if( itemsPanelTemplate == null )
      {
#if SILVERLIGHT
        itemsPanelTemplate = XamlReader.Load( ItemsPresenter.DefaultItemsPanelTemplateString ) as ItemsPanelTemplate;
#else
        XmlReader xmlReader = XmlReader.Create( new StringReader( ItemsPresenter.DefaultItemsPanelTemplateString ) );
        itemsPanelTemplate = XamlReader.Load( xmlReader ) as ItemsPanelTemplate;
#endif
      }

      // Use the ItemsPanelTemplate defined on the ListBox
      // if manually defined, else use the default one
      m_panel = itemsPanelTemplate.LoadContent() as PanelBase;

      if( m_panel == null )
        throw new ListBoxException( "The ItemsPanelTemplate root element must be a class derived from PanelBase." );

      // Shortcut to forward all IScrollInfo values in the
      // local implementation to the Panel
      m_panelIScrollInfo = m_panel as IScrollInfo;

      // Affect the Content of this ContentControl
      // to the Panel, which will be the only child
      this.Content = m_panel;
    }

    #endregion

    #region Private Fields

    private PanelBase m_panel;
    private IScrollInfo m_panelIScrollInfo;

    #endregion

    #region IScrollInfo Members

    bool IScrollInfo.CanHorizontallyScroll
    {
      get
      {
        return m_panelIScrollInfo.CanHorizontallyScroll;
      }
      set
      {
        m_panelIScrollInfo.CanHorizontallyScroll = value;
      }
    }

    bool IScrollInfo.CanVerticallyScroll
    {
      get
      {
        return m_panelIScrollInfo.CanVerticallyScroll;
      }
      set
      {
        m_panelIScrollInfo.CanVerticallyScroll = value;
      }
    }

    double IScrollInfo.ExtentHeight
    {
      get
      {
        return m_panelIScrollInfo.ExtentHeight;
      }
    }

    double IScrollInfo.ExtentWidth
    {
      get
      {
        return m_panelIScrollInfo.ExtentWidth;
      }
    }

    double IScrollInfo.HorizontalOffset
    {
      get
      {
        return m_panelIScrollInfo.HorizontalOffset;
      }
    }

    void IScrollInfo.LineDown()
    {
      m_panelIScrollInfo.LineDown();
    }

    void IScrollInfo.LineLeft()
    {
      m_panelIScrollInfo.LineLeft();
    }

    void IScrollInfo.LineRight()
    {
      m_panelIScrollInfo.LineRight();
    }

    void IScrollInfo.LineUp()
    {
      m_panelIScrollInfo.LineUp();
    }

#if SILVERLIGHT
    Rect IScrollInfo.MakeVisible( UIElement visual, Rect rectangle )
    {
      return m_panelIScrollInfo.MakeVisible( visual, rectangle );
    }
#else
    Rect IScrollInfo.MakeVisible( Visual visual, Rect rectangle )
    {
      return m_panelIScrollInfo.MakeVisible( visual, rectangle );
    }
#endif

    void IScrollInfo.MouseWheelDown()
    {
      m_panelIScrollInfo.MouseWheelDown();
    }

    void IScrollInfo.MouseWheelLeft()
    {
      m_panelIScrollInfo.MouseWheelLeft();
    }

    void IScrollInfo.MouseWheelRight()
    {
      m_panelIScrollInfo.MouseWheelRight();
    }

    void IScrollInfo.MouseWheelUp()
    {
      m_panelIScrollInfo.MouseWheelUp();
    }

    void IScrollInfo.PageDown()
    {
      m_panelIScrollInfo.PageDown();
    }

    void IScrollInfo.PageLeft()
    {
      m_panelIScrollInfo.PageLeft();
    }

    void IScrollInfo.PageRight()
    {
      m_panelIScrollInfo.PageRight();
    }

    void IScrollInfo.PageUp()
    {
      m_panelIScrollInfo.PageUp();
    }

    ScrollViewer IScrollInfo.ScrollOwner
    {
      get
      {
        return m_panelIScrollInfo.ScrollOwner;
      }
      set
      {
        m_panelIScrollInfo.ScrollOwner = value;
      }
    }

    void IScrollInfo.SetHorizontalOffset( double offset )
    {
      m_panelIScrollInfo.SetHorizontalOffset( offset );
    }

    void IScrollInfo.SetVerticalOffset( double offset )
    {
      m_panelIScrollInfo.SetVerticalOffset( offset );
    }

    double IScrollInfo.VerticalOffset
    {
      get
      {
        return m_panelIScrollInfo.VerticalOffset;
      }
    }

    double IScrollInfo.ViewportHeight
    {
      get
      {
        return m_panelIScrollInfo.ViewportHeight;
      }
    }

    double IScrollInfo.ViewportWidth
    {
      get
      {
        return m_panelIScrollInfo.ViewportWidth;
      }
    }

    #endregion
  }
}
